package dao

import (
	"errors"
	"fmt"
	"go.uber.org/zap"
	"smart-health-platforms/pkg"

	"math"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// 清洗规则：缺失值、异常值、标准化数据
// 缺失值
func IsMissing(value interface{}) (float64, bool) {
	val, err := stdValue(value)
	if err != nil {
		pkg.Warn("缺失值检查失败", zap.Error(err), zap.Any("value", value))
		return 0, false
	}
	if val == 0 {
		pkg.Warn("检测到空值（数值为0）", zap.Float64("value", val))
		return 0, false
	}
	return val, true
}

// 体温异常（35.0℃ ~ 42.0℃）
func ThermometerOutliers(temp float64) (float64, bool) {
	min1, max1 := 35.0, 42.0
	if temp >= min1 && temp <= max1 {
		return temp, true
	}
	pkg.Warn("体温超出正常范围", zap.Float64("temp", temp), zap.Float64("min", min1),
		zap.Float64("max", max1))
	return 0, false
}

// 脉率异常（60 ~ 100 次/分）
func OximeterOutliers(pr float64) (float64, bool) {
	min2, max2 := 60.0, 100.0
	if pr >= min2 && pr <= max2 {
		return pr, true
	}
	pkg.Warn("脉率超出正常范围", zap.Float64("pr", pr),
		zap.Float64("min", min2), zap.Float64("max", max2))
	return 0, false
}

// 血糖异常（3.9 ~ 7.8 mmol/L，空腹示例）
func GlucoseOutliers(glucose float64) (float64, bool) {
	min3, max3 := 3.9, 7.8
	if glucose >= min3 && glucose <= max3 {
		return glucose, true
	}
	pkg.Warn("血糖超出正常范围", zap.Float64("glucose", glucose), zap.Float64("min", min3),
		zap.Float64("max", max3))
	return 0, false
}

// 标准化数据结构
type StandardizedData struct {
	Timestamp    time.Time   // UTC 时间戳
	TimestampStr string      // 格式化时间字符串
	MeasureValue float64     // 标准化测量值
	OriginalVal  interface{} // 原始输入值
	Unit         string      // 标准化单位
}

// 支持的时间格式（兼容多格式输入）
var timeFormats = []string{
	time.RFC3339, "2006-01-02 15:04:05", "2006/01/02 15:04:05",
	"2006-01-02", "20060102150405", "01-02-2006 15:04:05",
}

// 统一标准化入口：时间、值、单位
func StandardizeData(timestamp, measureVal interface{}, unit string) (StandardizedData, error) {
	var res StandardizedData
	// 1. 时间戳标准化
	ts, err := stdTimestamp(timestamp)
	if err != nil {
		return res, fmt.Errorf("时间戳标准化失败: %w", err)
	}
	res.Timestamp = ts
	res.TimestampStr = ts.Format("2006-01-02 15:04:05")
	// 2. 测量值标准化
	val, err := stdValue(measureVal)
	if err != nil {
		return res, fmt.Errorf("测量值标准化失败: %w", err)
	}
	res.MeasureValue = val
	res.OriginalVal = measureVal
	// 3. 单位标准化
	res.Unit = stdUnit(unit)
	return res, nil
}

// 时间戳标准化（兼容 string/int64/time.Time）
func stdTimestamp(timestamp interface{}) (time.Time, error) {
	switch t := timestamp.(type) {
	case time.Time:
		return t.UTC(), nil
	case string:
		for _, fmt := range timeFormats {
			if pt, err := time.Parse(fmt, t); err == nil {
				return pt.UTC(), nil
			}
		}
		if ts, err := strconv.ParseInt(t, 10, 64); err == nil {
			return parseTS(ts), nil
		}
		err := errors.New("不支持的时间格式")
		pkg.Warn("时间戳解析失败", zap.Error(err), zap.String("timestamp", t))
		return time.Time{}, err
	case int64:
		return parseTS(t), nil
	default:
		err := errors.New("不支持的时间类型")
		pkg.Warn("时间戳解析失败", zap.Error(err), zap.Any("timestamp", timestamp))
		return time.Time{}, err
	}
}

// 解析时间戳（自动转换秒级/毫秒级）
func parseTS(ts int64) time.Time {
	if ts > 1e12 { // 毫秒转秒
		ts /= 1000
	}
	return time.Unix(ts, 0).UTC()
}

// 测量值标准化（兼容 string/int/float 等）
func stdValue(v interface{}) (float64, error) {
	switch val := v.(type) {
	case int, int64, float32, float64:
		return toFloat64(val), nil
	case string:
		cleaned := regexp.MustCompile(`[^0-9\-.]`).ReplaceAllString(val, "")
		if cleaned == "" {
			err := errors.New("无法提取有效数值")
			pkg.Warn("测量值解析失败", zap.Error(err), zap.String("raw_value", val))
			return 0, err
		}
		num, err := strconv.ParseFloat(cleaned, 64)
		if err != nil {
			pkg.Warn("数值转换失败", zap.Error(err), zap.String("cleaned_value", cleaned))
			return 0, err
		}
		return num, nil
	default:
		err := errors.New("不支持的数值类型")
		pkg.Warn("测量值解析失败", zap.Error(err), zap.Any("raw_value", v))
		return 0, err
	}
}

// 通用类型转 float64（辅助函数）
func toFloat64(v interface{}) float64 {
	switch val := v.(type) {
	case int:
		return float64(val)
	case int64:
		return float64(val)
	case float32:
		return float64(val)
	case float64:
		return val
	default:
		return 0
	}
}

// 单位标准化（统一符号）
func stdUnit(unit string) string {
	unit = strings.TrimSpace(unit)
	switch strings.ToLower(unit) {
	case "c", "℃", "celcius", "摄氏度":
		return "℃"
	case "bpm", "次/分", "次每分钟":
		return "次/分"
	case "mmol/l", "mmol", "毫摩尔/升":
		return "mmol/L"
	default:
		return unit
	}
}

// 体温清洗（整合标准化+缺失+异常检查）
func ThermometerClean(timestamp, rawTemp interface{}, unit string) (StandardizedData, error) {
	stdData, err := StandardizeData(timestamp, rawTemp, unit)
	if err != nil {
		return stdData, fmt.Errorf("体温数据预处理失败: %w", err)
	}
	val, ok := IsMissing(stdData.MeasureValue)
	if !ok {
		err := errors.New("缺失值，跳过处理")
		pkg.Warn("体温清洗终止", zap.Error(err))
		return stdData, err
	}
	validVal, ok := ThermometerOutliers(val)
	if !ok {
		err := errors.New("异常值，跳过处理")
		pkg.Warn("体温清洗终止", zap.Error(err), zap.Float64("temp", val))
		return stdData, err
	}
	// 新增：四舍五入保留1位小数
	validVal = roundToOneDecimal(validVal)
	stdData.MeasureValue = validVal
	return stdData, nil
}

// 脉率清洗
func OximeterClean(timestamp, rawPR interface{}, unit string) (StandardizedData, error) {
	stdData, err := StandardizeData(timestamp, rawPR, unit)
	if err != nil {
		return stdData, fmt.Errorf("脉率数据预处理失败: %w", err)
	}

	val, ok := IsMissing(stdData.MeasureValue)
	if !ok {
		err := errors.New("缺失值，跳过处理")
		pkg.Warn("脉率清洗终止", zap.Error(err))
		return stdData, err
	}

	validVal, ok := OximeterOutliers(val)
	if !ok {
		err := errors.New("异常值，跳过处理")
		pkg.Warn("脉率清洗终止", zap.Error(err), zap.Float64("pr", val))
		return stdData, err
	}

	// 新增：四舍五入保留1位小数
	validVal = roundToOneDecimal(validVal)
	stdData.MeasureValue = validVal

	return stdData, nil
}

// 血糖清洗
func GlucoseClean(timestamp, rawGlucose interface{}, unit string) (StandardizedData, error) {
	stdData, err := StandardizeData(timestamp, rawGlucose, unit)
	if err != nil {
		return stdData, fmt.Errorf("血糖数据预处理失败: %w", err)
	}

	val, ok := IsMissing(stdData.MeasureValue)
	if !ok {
		err := errors.New("缺失值，跳过处理")
		pkg.Warn("血糖清洗终止", zap.Error(err))
		return stdData, err
	}

	validVal, ok := GlucoseOutliers(val)
	if !ok {
		err := errors.New("异常值，跳过处理")
		pkg.Warn("血糖清洗终止", zap.Error(err), zap.Float64("glucose", val))
		return stdData, err
	}

	// 新增：四舍五入保留1位小数
	validVal = roundToOneDecimal(validVal)
	stdData.MeasureValue = validVal
	return stdData, nil
}
func roundToOneDecimal(val float64) float64 {
	return math.Round(val*10) / 10
}
